package com.stars.easyms.redis.interceptor;

import com.stars.easyms.base.util.GenericTypeUtil;
import com.stars.easyms.base.util.ReflectUtil;
import com.stars.easyms.base.util.TimeUtil;
import com.stars.easyms.redis.annotion.RedisSetMembers;
import com.stars.easyms.redis.exception.RedisInterceptorException;
import org.aopalliance.intercept.MethodInvocation;
import org.springframework.util.CollectionUtils;

import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.concurrent.TimeUnit;

/**
 * <p>className: RedisListRangeInterceptor</p>
 * <p>description: RedisListRange注解拦截器</p>
 *
 * @author
 * @date 2019-12-24 17:44
 */
public class RedisSetMembersInterceptor extends AbstractRedisInterceptor<RedisSetMembers> {

    @Override
    Object invoke(MethodInvocation methodInvocation, RedisSetMembers redisSetMembers) throws RedisInterceptorException {
        Object result = null;
        if(isEnabled()){
            Method pointMethod = methodInvocation.getMethod();
            Class<?> returnType = pointMethod.getReturnType();
            Type genericReturnType = pointMethod.getGenericReturnType();
            boolean isInvalidReturnType = !(List.class.isAssignableFrom(returnType) || Set.class.isAssignableFrom(returnType));
            if (isInvalidReturnType) {
                logger.error("Method '{}' returnType should be List<T> or Set<T>!", ReflectUtil.getMethodFullName(pointMethod));
            }
            String redisKey = getRedisKey(methodInvocation, redisSetMembers.group());
            boolean override = redisSetMembers.override();
            if (!(genericReturnType instanceof ParameterizedType)) {
                result = easyMsRedisTemplate.setMembers(redisKey);
            } else {
                Class clazz = GenericTypeUtil.getGenericClass(genericReturnType, 0);
                result = easyMsRedisTemplate.setMembers(redisKey, clazz);
            }
            /**
             * 去除结果集合为true
             */
            if(!CollectionUtils.isEmpty((Set)result)){
                if(override){
                    easyMsRedisTemplate.setPop(redisKey);
                    easyMsRedisTemplate.setAdd(redisKey, (Set<Object>)result);
                }
                Long expire = TimeUtil.parseToMilliseconds(redisSetMembers.expire());
                boolean isSetExpire = expire != null && expire > 0 && easyMsRedisTemplate.getExpire(redisKey, TimeUnit.MILLISECONDS) <= 0;
                if (isSetExpire) {
                    easyMsRedisTemplate.expire(redisKey, expire, TimeUnit.MILLISECONDS);
                }
                /**
                 * 返回类型为List时候 进行转化
                 */
                if(List.class.isAssignableFrom(returnType)){
                    List list =  new ArrayList<>((Set)result);
                    result =list;
                }
                return  result;
            }
            result = proceed(methodInvocation);
            if((List.class.isAssignableFrom(returnType) && !CollectionUtils.isEmpty((List)result))
                    || (Set.class.isAssignableFrom(returnType) && !CollectionUtils.isEmpty((Set)result))){
                if(List.class.isAssignableFrom(returnType)){
                    easyMsRedisTemplate.setAdd(redisKey, (List<Object>) result);
                }else if(Set.class.isAssignableFrom(returnType)){
                    easyMsRedisTemplate.setAdd(redisKey, (Set<Object>) result);
                }else{
                    easyMsRedisTemplate.setAdd(redisKey, result);
                }
                Long expire = getExpire(methodInvocation);
                expire = expire != null ? expire : TimeUtil.parseToMilliseconds(redisSetMembers.expire());
                boolean isSetExpire = expire != null && expire > 0 && easyMsRedisTemplate.getExpire(redisKey, TimeUnit.MILLISECONDS) <= 0;
                if (isSetExpire) {
                    easyMsRedisTemplate.expire(redisKey, expire, TimeUnit.MILLISECONDS);
                }
            }
        }
        return result;
    }
}